/* eslint-disable */
import type { Uri } from './uri';
import { uri } from './uri';
import { Bus } from './bus';

type Events = Record<number, string>;

export interface SocketOptions {
  host?: string;
  heartbeat?: number;
}
export class Socket {
  private host: string;
  private heartbeat: number;
  private ping: object;
  private heartbeatTimer: null | number;
  private ws: null | WebSocket;
  private bus: Bus;
  private shutdown: boolean;
  private queue: object[];
  private events: Events;
  constructor(options?: SocketOptions) {
    const _options = Object.assign({}, options);
    // ws的host地址
    let host;
    const protocol = window.location.protocol.replace('http', 'ws');

    // if (process.env.NODE_ENV === 'production') {
    //   host = `${protocol}${window.location.host}${HX_WS_SERVER}`;
    // } else {
    //   host = `wss:${HX_WS_SERVER}`;
    // }
    // this.host = `${host}?token=${localStorage.getItem('token')}`;
    this.host = `wss://${window.location.hostname}/mmc-socket/websocket-server/ws/asset?auth-type=hx-ykdj-web&token=5fd23192-d680-4459-817e-6e21848dc5bd`;
    // 心跳频率
    this.heartbeat = _options.heartbeat || 58000;
    // 心跳测试参数
    this.ping = { code: 10000 };
    // 心跳定时器id
    this.heartbeatTimer = null;
    // socket对象
    this.ws = null;
    // 事件总线
    this.bus = new Bus();
    // 注册的事件队列
    this.events = {};
    // 消息队列
    this.queue = [];
    // 是否是手动关闭
    this.shutdown = false;
    // 调用初始化
    this.init();
  }
  // 初始化
  init(): void {
    const _this = this;

    // 注册事件
    _this.registerEvent(uri);

    // 将关闭标识设为true
    _this.shutdown = false;

    _this.ws = new WebSocket(_this.host);

    // 连接成功
    _this.ws.onopen = function open(e: Event) {
      console.log('连接成功');
      _this.startHeartbeat();
      if (_this.queue.length > 0) {
        _this.clearQueue();
      }
    };

    // 收到消息
    _this.ws.onmessage = function message(e) {
      _this.bus.post('message', e);
      _this.triggerEvents(e);
    };

    // 连接出错
    _this.ws.onerror = function error(e: Event) {
      _this.bus.post('error', e);
      _this.reconnect();
    };

    // 连接关闭
    _this.ws.onclose = function close(e: Event) {
      _this.bus.post('close', e);
      if (_this.shutdown) {
        return;
      }
      _this.reconnect();
    };
  }
  // 监听事件
  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
  triggerEvents(e: any): void {
    const _this = this,
      { events } = _this;
    if (_this.ws && _this.ws.readyState === 1) {
      const data = JSON.parse(e.data);
      if (data.uri && events[data.uri]) {
        _this.bus.post(events[data.uri], data);
      }
    }
  }
  // 开始心跳
  startHeartbeat(): void {
    const _this = this;
    const { ping, heartbeat } = _this;

    clearInterval(Number(_this.heartbeatTimer));
    this.send(ping);
    _this.heartbeatTimer = window.setInterval(() => {
      this.send(ping);
    }, heartbeat);
  }
  // 停止心跳
  stopHeartbeat(): void {
    clearInterval(Number(this.heartbeatTimer));
  }
  // 关闭连接
  close(): void {
    this.ws && this.ws.close();
    this.ws = null;
    this.shutdown = true;
    this.heartbeatTimer;
  }
  // 发送消息
  send(data: object): void {
    const _this = this;
    const message = JSON.stringify(data);

    try {
      if (_this.ws && _this.ws.readyState === 1) {
        _this.ws.send(message);
        console.log(`[socket] 消息发送: ${message}`);
      } else {
        this.queue.push(data);
        console.log(`[socket] 消息入队: ${message}`);
      }
    } catch (error) {
      _this.reconnect();
    }
  }
  // 重新连接
  reconnect(): void {
    const _this = this;
    _this.stopHeartbeat();
    _this.close();
    setTimeout(() => {
      _this.ws = null;
      _this.init();
      _this.bus.post('reconnect');
    }, 2000);
  }
  // 清空消息队列
  clearQueue(): void {
    console.log('清空消息队列');
    while (this.queue.length > 0) {
      const msg: Object | undefined = this.queue.shift();
      if (msg) {
        this.send(msg);
      }
    }
  }
  // 注册事件
  registerEvent(eventsList: Uri[]): void {
    const _this = this;
    const { events } = _this;

    eventsList.forEach((item) => {
      events[Number(item.uri)] = item.event;
    });
  }
  // 向外暴露一个绑定方法
  on(type: string, fn: Function): void {
    this.bus.subscribe(type, fn);
  }
  // 向外暴露一个解绑方法
  off(type: string, fn: Function): void {
    this.bus.unsubscribe(type, fn);
  }
}

export default { Socket };
